<!DOCTYPE html>
<html>

<head>
  <title>「面向对象」在线Web高级正式课</title>
  <meta charset='utf-8'>
  <link href='https://cdn.maxiang.io/res-min/themes/marxico.css' rel='stylesheet'>
  <style>
    .note-content {
      font-family: "Helvetica Neue", Arial, "Hiragino Sans GB", STHeiti, "Microsoft YaHei", "WenQuanYi Micro Hei", SimSun, Song, sans-serif;
    }

    #preview-contents {
      margin-top: 0;
    }
  </style>
</head>

<body>
  <div id='preview-contents' class='note-content'>
    <h4>专题：JS中数据类型检测汇总</h4>
    <ul>
      <li>
        <p>typeof</p>
        <ul>
          <li>
            <p>底层原理</p>
          </li>
        </ul>
      </li>
      <li>
        <p>instanceof </p>

        <ul>
          <li>
            <p>底层原理及相关问题</p>
          </li>
          <li>
            <p>Symbol.hasInstance</p>
          </li>
          <li>
            <p>重写instanceof</p>
          </li>
        </ul>
      </li>
      <li>
        <p>constructor</p>
      </li>
      <li>
        <p>Object.prototype.toString.call(value)</p>

        <ul>
          <li>
            <p>value[Symbol.toStringTag]</p>
          </li>
        </ul>
      </li>
    </ul>

    <p><strong>重写instanceof</strong></p>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">instance_of</span>(<span class="hljs-params">obj, Ctor</span>) </span>{
</div><div class="hljs-line">    <span class="hljs-comment">// 数据格式准确性校验</span>
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (Ctor == <span class="hljs-literal">null</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">"Right-hand side of 'instanceof' is not an object"</span>);
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (!Ctor.prototype) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">"Function has non-object prototype 'undefined' in instanceof check"</span>);
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> Ctor !== <span class="hljs-string">"function"</span>) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">TypeError</span>(<span class="hljs-string">"Right-hand side of 'instanceof' is not callable"</span>);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 原始类型直接忽略</span>
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (obj == <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (!<span class="hljs-regexp">/^(object|function)$/</span>.test(<span class="hljs-keyword">typeof</span> obj)) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 先检测是否有 Symbol.hasInstance 这个属性</span>
</div><div class="hljs-line">    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> Ctor[<span class="hljs-built_in">Symbol</span>.hasInstance] === <span class="hljs-string">"function"</span>) <span class="hljs-keyword">return</span> Ctor[<span class="hljs-built_in">Symbol</span>.hasInstance](obj);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 最后才会按照原型链进行处理</span>
</div><div class="hljs-line">    <span class="hljs-keyword">let</span> prototype = <span class="hljs-built_in">Object</span>.getPrototypeOf(obj);
</div><div class="hljs-line">    <span class="hljs-keyword">while</span> (prototype) {
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (prototype === Ctor.prototype) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
</div><div class="hljs-line">        prototype = <span class="hljs-built_in">Object</span>.getPrototypeOf(prototype);
</div><div class="hljs-line">    }
</div><div class="hljs-line">    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
</div><div class="hljs-line">}
</div></code></pre>

    <p><strong>JQ中数据类型检测方法</strong></p>
    <pre class="prettyprint hljs-dark"><code class="language-javascript hljs"><div class="hljs-line">(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
</div><div class="hljs-line"><span class="hljs-meta">    "use strict"</span>;
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> getProto = <span class="hljs-built_in">Object</span>.getPrototypeOf,
</div><div class="hljs-line">        class2type = {},
</div><div class="hljs-line">        toString = class2type.toString,
</div><div class="hljs-line">        hasOwn = class2type.hasOwnProperty,
</div><div class="hljs-line">        fnToString = hasOwn.toString,
</div><div class="hljs-line">        ObjectFunctionString = fnToString.call(<span class="hljs-built_in">Object</span>);
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 专门进行数据类型检测的办法 </span>
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> toType = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">toType</span>(<span class="hljs-params">obj</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (obj == <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> obj + <span class="hljs-string">""</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> obj !== <span class="hljs-string">"object"</span> &amp;&amp; <span class="hljs-keyword">typeof</span> obj !== <span class="hljs-string">"function"</span>) <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> obj;
</div><div class="hljs-line">        <span class="hljs-keyword">var</span> reg = <span class="hljs-regexp">/^\[object ([0-9A-Za-z]+)\]$/</span>,
</div><div class="hljs-line">            value = reg.exec(toString.call(obj))[<span class="hljs-number">1</span>] || <span class="hljs-string">"object"</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> value.toLowerCase();
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 检测是否为一个函数</span>
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> isFunction = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isFunction</span>(<span class="hljs-params">obj</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> obj === <span class="hljs-string">"function"</span> &amp;&amp; <span class="hljs-keyword">typeof</span> obj.nodeType !== <span class="hljs-string">"number"</span>;
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 检测是否为一个window对象</span>
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> isWindow = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isWindow</span>(<span class="hljs-params">obj</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> obj != <span class="hljs-literal">null</span> &amp;&amp; obj === obj.window;
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 检测是否为数组或者类数组</span>
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> isArrayLike = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isArrayLike</span>(<span class="hljs-params">obj</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">var</span> length = !!obj &amp;&amp; <span class="hljs-string">"length"</span> <span class="hljs-keyword">in</span> obj &amp;&amp; obj.length,
</div><div class="hljs-line">            type = toType(obj);
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (isFunction(obj) || isWindow(obj)) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> type === <span class="hljs-string">"array"</span> || length === <span class="hljs-number">0</span> ||
</div><div class="hljs-line">            <span class="hljs-keyword">typeof</span> length === <span class="hljs-string">"number"</span> &amp;&amp; length &gt; <span class="hljs-number">0</span> &amp;&amp; (length - <span class="hljs-number">1</span>) <span class="hljs-keyword">in</span> obj;
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 检测是否为纯粹的对象</span>
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> isPlainObject = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isPlainObject</span>(<span class="hljs-params">obj</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">var</span> proto, Ctor;
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (!obj || toType(obj) !== <span class="hljs-string">"object"</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
</div><div class="hljs-line">        proto = getProto(obj);
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (!proto) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
</div><div class="hljs-line">        Ctor = hasOwn.call(proto, <span class="hljs-string">"constructor"</span>) &amp;&amp; proto.constructor;
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> <span class="hljs-keyword">typeof</span> Ctor === <span class="hljs-string">"function"</span> &amp;&amp; fnToString.call(Ctor) === ObjectFunctionString;
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 检测是否为空对象</span>
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> isEmptyObject = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isEmptyObject</span>(<span class="hljs-params">obj</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (obj == <span class="hljs-literal">null</span>) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
</div><div class="hljs-line">        <span class="hljs-keyword">var</span> keys = <span class="hljs-built_in">Object</span>.keys(obj);
</div><div class="hljs-line">        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">typeof</span> <span class="hljs-built_in">Symbol</span> !== <span class="hljs-string">"undefined"</span>) {
</div><div class="hljs-line">            keys = keys.concat(<span class="hljs-built_in">Object</span>.getOwnPropertySymbols(obj));
</div><div class="hljs-line">        }
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> keys.length === <span class="hljs-number">0</span>;
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    <span class="hljs-comment">// 检测是否为数字</span>
</div><div class="hljs-line">    <span class="hljs-keyword">var</span> isNumeric = <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">isNumeric</span>(<span class="hljs-params">obj</span>) </span>{
</div><div class="hljs-line">        <span class="hljs-keyword">var</span> type = toType(obj);
</div><div class="hljs-line">        <span class="hljs-keyword">return</span> (type === <span class="hljs-string">"number"</span> || type === <span class="hljs-string">"string"</span>) &amp;&amp; !<span class="hljs-built_in">isNaN</span>(+obj);
</div><div class="hljs-line">    };
</div><div class="hljs-line"><wbr>
</div><div class="hljs-line">    ......
</div><div class="hljs-line">})();
</div></code></pre>
  </div>
</body>

</html>